﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Collections;
using LED_Editor.ControllerProgramming;
using System.Windows.Forms;
using System.Drawing;

namespace LED_Editor.Model {



	//public interface  ILedController
	//{
	//    byte[] ReadBytes();
	//    void WriteBytes(params byte[] bytes);
	//}



	public struct FrameInterval {
		public FrameInterval(int start, int end)
			: this() {
			Start = start;
			End = end;
		}

		public int Start { get; private set; }
		public int End { get; private set; }
	}

	public class ControllerHelper {
		public static string GetQueryDescription(byte query) {
			return Convert.ToChar(query).ToString();
		}
	}

	public class Controller : IDisposable {
		public Controller() {
			_frames = new FrameStructCollection();
		}


		public Controller(SerialPort serialPort)
			: this() {
			_port = serialPort;
		}

		public event LoggingEventHandler Logging {
			add { ControllerProgrammingStrategy.Logging += value; }
			remove { ControllerProgrammingStrategy.Logging -= value; }
		}



		private IControllerProgrammingStrategy _controllerProgrammingStrategy;

		protected virtual IControllerProgrammingStrategy ControllerProgrammingStrategy {
			get {
				if (_controllerProgrammingStrategy == null)
					// _controllerProgrammingStrategy = new SerialPortProgrammingStrategy(_port);
					_controllerProgrammingStrategy = new XtendedSerialPortProgrammingStrategy(_port);
				return _controllerProgrammingStrategy;
			}
		}


		public byte Address { get { return ControllerProgrammingStrategy.Address; } set { ControllerProgrammingStrategy.Address = value; } }

		protected void Log(string message) {
			ControllerProgrammingStrategy.Log(message);
		}

		protected void Log(string message, params string[] args) {
			Log(message, args);
		}

		private SerialPort _port;

		public void SetBaudRate(int rate) {
			if (!_port.IsOpen) {
				_port.BaudRate = rate;
			}
		}
		public void SetPortName(string name) {
			if (!_port.IsOpen) {
				_port.PortName = name;
			}
		}


		private FrameStructCollection _frames;


		public IList<FrameStruct> Frames {
			get {
				return _frames;
			}
		}

		public void SetFrames(IEnumerable<FrameStruct> frames) {
			IEnumerator<FrameStruct> it = frames.GetEnumerator();
			_frames.Clear();
			while (it.MoveNext()) {
				_frames.Add(it.Current);
			}
		}



		public FrameStruct GetFrameByElapsedTime(int elapsedIntervals) {
			foreach (FrameStruct item in Frames) {
				if (item.StartMarker <= elapsedIntervals && item.StartMarker + item.Duration >= elapsedIntervals)
					return item;
			}
			return FrameStruct.Empty;
		}

		public int GetFrameIndexByElapsedTime(int elapsedIntervals) {
			FrameStruct frame = GetFrameByElapsedTime(elapsedIntervals);

			if (frame.Equals(FrameStruct.Empty))
				return -1;

			return _frames.IndexOf(frame);
		}


		public int TotalFramesDuration {
			get {
				int total = 0;
				foreach (var item in Frames) {
					total += item.Duration;
				}
				return total;
			}
		}

		public int TotalFramesDurationMilliseconds {
			get {
				return TotalFramesDuration * 10;
			}
		}


		public virtual void OpenConnection() {
			ControllerProgrammingStrategy.OpenConnection();
		}
		public virtual void CloseConnection() {
			ControllerProgrammingStrategy.CloseConnection();

		}

		public virtual bool IsReadyForProgramming {
			get {
				int timeout = ControllerProgrammingStrategy.Timeout;
				try {
					ControllerProgrammingStrategy.Timeout = 2000;
					if (!ControllerProgrammingStrategy.IsOpen) {
						OpenConnection();
					}
					return ControllerProgrammingStrategy.IsReadyForProgramming;
				} finally {
					if (ControllerProgrammingStrategy.IsOpen) {
						CloseConnection();
					}
					ControllerProgrammingStrategy.Timeout = timeout;
					Application.DoEvents();
				}
			}
		}

		public virtual bool SafeIsReadyForProgramming {
			get {
				try {
					return IsReadyForProgramming;
				} catch {
					return false;
				}
			}
		}



		public bool TryOpenConnection(out Exception error) {
			try {
				OpenConnection();
				error = null;
				return true;
			} catch (Exception ex) {
				error = ex;
				return false;
			}
		}


		public void ReportError(string errorText) {
			throw new ControllerException(string.Format("Состояние: {0}, Адрес: {1}. {2}", State, Address, errorText));
		}
		public void ReportInvalidAnswer(byte answer) {
			ReportError(string.Format("Неверный ответ контроллера: {0}", Convert.ToChar(answer)));
		}


		public ControllerState State { get { return ControllerProgrammingStrategy.State; } }

		public void Programme() {
			ControllerProgrammingStrategy.Programme(Frames);
		}

		public void SendQuery(Query query) {
			ControllerProgrammingStrategy.SendQuery(query);
		}

		#region IDisposable Members

		public void Dispose() {
			if (_port != null) {
				if (_port.IsOpen) {
					_port.Close();
				}
				_port.Dispose();
			}
		}

		#endregion
	}
}
